"""
意图识别智能体

基于LLM的自然语言意图识别，识别用户输入的意图类型并提取相关参数。
"""

import json
import re
from typing import Dict, Any, List, Optional
from langchain_core.prompts import PromptTemplate
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage

from agents import BaseAgent, LLMConfig


# 意图识别prompt模板
INTENT_RECOGNITION_PROMPT = PromptTemplate.from_template("""
你是一个专业的债券分析意图识别智能体，负责理解用户的自然语言输入并识别用户意图。

你需要从用户输入中识别以下信息：

1. **意图类型** (intent_type)：
    - "conversation": 对话类请求（如："你好"、"谢谢"、"你能做什么"、"什么是可转债"）
    - "analysis": 分析类请求（如："分析南航转债"、"帮我分析113050"）
    - "stock_analysis": 股票分析类请求（如："分析中国石化股票"、"帮我看看000001"）
    - "comparison": 比较类请求（如："比较113050和113051"、"哪个债券更好"）
    - "query": 查询类请求（如："113050最近表现怎么样"、"查询南航转债基本信息"）
    - "follow_up": 追问类请求（如："上次那个债券怎么样了"、"刚才的分析能详细说说吗"）

2. **债券代码** (bond_codes)：
    - 提取6位数字债券代码（如：113050, 113051）
    - 支持多个债券代码
    - 从用户输入中提取所有6位数字作为债券代码
    - 如果用户提到债券名称，尝试识别对应的常见代码

3. **股票代码** (stock_codes)：
    - 提取6位数字股票代码（如：000001, 600000）
    - 支持多个股票代码
    - 从用户输入中提取所有6位数字作为股票代码
    - 如果用户提到股票名称，尝试识别对应的常见代码

3. **分析维度** (analysis_dimensions)：
    - "fundamental": 基本面分析
    - "technical": 技术面分析  
    - "market": 市场分析
    - "risk": 风险分析
    - "macro": 宏观分析
    - 如果未明确指定，默认为完整分析

4. **查询类型** (query_type)，仅当意图为"query"时：
    - "basic_info": 基本信息查询
    - "market_data": 行情数据查询
    - "news": 新闻查询
    - "rating": 评级查询
    - "performance": 表现查询

5. **时间范围** (time_range)：
    - 提取用户指定的时间范围（如："最近"、"近一个月"、"今年"）
    - 如果未指定，默认为"recent"

6. **置信度** (confidence)：
    - 对识别结果的置信度评分（0.0-1.0）

💭 对话历史信息：
{recent_history}

用户输入：{user_input}

请分析上述用户输入，并返回以下JSON格式的结果：

```json
{{
  "intent_type": "conversation|analysis|stock_analysis|comparison|query|follow_up",
  "bond_codes": ["113050", "113051"],
  "stock_codes": ["000001", "600000"],
  "analysis_dimensions": ["fundamental","technical", "market", "risk", "macro"],
  "query_type": "basic_info|market_data|news|rating|performance",
  "time_range": "recent|1month|3months|1year|custom",
  "confidence": 0.95,
  "extracted_keywords": ["关键词1", "关键词2"],
  "raw_text": "原始用户输入",
  "analysis_mode": "full|partial",
  "enabled_agents": ["fundamental", "market", "risk", "macro"],
  "context_awareness": {{
    "recent_bond_codes": ["最近分析的债券代码"],
    "recent_stock_codes": ["最近分析的股票代码"],
    "preferred_dimensions": ["用户偏好的分析维度"],
    "follow_up_target": "追问目标的具体内容"
  }}
}}
```

重要规则：
1. 如果无法识别债券代码，设置为空数组[]
2. 如果意图类型不是"query"，则query_type为null
3. analysis_mode根据analysis_dimensions确定："full"表示全部维度，"partial"表示部分维度
4. enabled_agents根据analysis_dimensions映射具体的智能体名称
5. 置信度应该反映对整体识别结果的信心程度
6. 必须返回有效的JSON格式，不要包含额外的解释文字
7. 对于"conversation"和"follow_up"意图，bond_codes可以为空，analysis_dimensions和enabled_agents保持默认值
8. context_awareness字段提供上下文感知信息，帮助后续处理

开始分析：
""")


class GeneralIntentRecognitionAgent(BaseAgent):
    """通用意图识别智能体"""
    
    def __init__(self, llm_config: Optional[LLMConfig] = None):
        super().__init__(
            name="intent_recognition",
            description="识别用户意图和分析需求",
            llm_config=llm_config
        )
    
    def get_tools(self) -> list:
        """意图识别不需要工具"""
        return []
    
    def get_system_prompt(self) -> str:
        """获取系统提示词"""
        return "你是一个专业的意图识别智能体，负责解析用户的债券分析需求。"
    
    async def analyze(self, user_input: str, recent_history: str = "", **kwargs) -> Dict[str, Any]:
        """
        识别用户意图

        Args:
            user_input: 用户输入的自然语言文本
            recent_history: 最近的对话历史摘要
            **kwargs: 额外参数

        Returns:
            结构化的意图识别结果
        """
        try:
            # 验证输入
            if not user_input or not isinstance(user_input, str):
                return self.handle_error(
                    ValueError("用户输入不能为空"), str(user_input)
                )

            self.logger.info(f"开始识别用户意图: '{user_input[:50]}...'")

            # 调试：尝试正则表达式提取债券代码
            import re
            bond_codes_regex = re.findall(r'\b\d{6}\b', user_input)
            self.logger.info(f"正则表达式提取的债券代码: {bond_codes_regex}")

            # 执行意图识别
            result = await self._execute_recognition(user_input, recent_history)

            # 调试：记录识别结果
            self.logger.info(f"意图识别结果: intent_type={result.get('intent_type')}, confidence={result.get('confidence')}, bond_codes={result.get('bond_codes')}")

            # 格式化响应
            return self.format_response(result)

        except Exception as e:
            return self.handle_error(e, user_input, "意图识别")
    
    async def _execute_recognition(self, user_input: str, recent_history: str) -> Dict[str, Any]:
        """执行意图识别逻辑"""
        try:
            # 构建消息
            messages = [
                SystemMessage(
                    content="你是一个专业的意图识别智能体，负责解析用户的债券分析需求。"
                ),
                HumanMessage(
                    content=INTENT_RECOGNITION_PROMPT.format(
                        user_input=user_input,
                        recent_history=recent_history or "（无历史记录）",
                    )
                ),
            ]
            
            # 调用LLM
            response = self.llm.invoke(messages)
            output = response.content if hasattr(response, 'content') else str(response)
            
            # 确保output是字符串类型
            if isinstance(output, list):
                output = ' '.join([str(item) for item in output])
            elif not isinstance(output, str):
                output = str(output)
            
            # 解析JSON结果
            parsed_result = self._parse_json_output(output)
            
            # 验证和补充结果
            validated_result = self._validate_and_enhance_result(parsed_result, user_input)
            
            # 添加推理过程
            validated_result["reasoning_steps"] = self._extract_reasoning_steps(output)
            validated_result["reasoning_process"] = " → ".join(validated_result["reasoning_steps"][:3])
            
            # 添加元数据
            validated_result["agent_type"] = self.name
            validated_result["status"] = "success"
            
            return validated_result
            
        except Exception as e:
            # 返回默认结果
            return self._get_default_result(user_input, str(e))
    
    def _parse_json_output(self, output: str) -> Dict[str, Any]:
        """解析LLM输出的JSON"""
        try:
            # 直接尝试解析
            return json.loads(output)
        except json.JSONDecodeError:
            # 查找JSON块
            json_patterns = [
                r"```json\s*(\{.*?\})\s*```",
                r"```\s*(\{.*?\})\s*```",
                r"(\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\})",
            ]
            
            for pattern in json_patterns:
                matches = re.findall(pattern, output, re.DOTALL)
                for match in matches:
                    try:
                        cleaned_json = match.strip()
                        return json.loads(cleaned_json)
                    except json.JSONDecodeError:
                        continue
            
            # 如果都失败了，抛出异常
            raise json.JSONDecodeError("无法解析JSON", output, 0)
    
    def _validate_and_enhance_result(self, result: Dict[str, Any], user_input: str) -> Dict[str, Any]:
        """验证和增强解析结果"""
        
        # 确保必需字段存在
        required_fields = {
            "intent_type": "conversation",
            "bond_codes": [],
            "stock_codes": [],
            "analysis_dimensions": ["fundamental", "technical", "market", "risk", "macro"],
            "query_type": None,
            "time_range": "recent",
            "confidence": 0.5,
            "extracted_keywords": [],
            "raw_text": user_input,
            "analysis_mode": "full",
            "enabled_agents": ["fundamental", "technical", "market", "risk", "macro"],
        }
        
        for field, default_value in required_fields.items():
            if field not in result:
                result[field] = default_value
        
        # 验证intent_type
        valid_intents = ["conversation", "analysis", "stock_analysis", "comparison", "query", "follow_up"]
        if result["intent_type"] not in valid_intents:
            result["intent_type"] = "conversation"
        
        # 验证bond_codes格式
        if not isinstance(result["bond_codes"], list):
            result["bond_codes"] = []

        # 过滤有效的债券代码（6位数字）
        valid_codes = []
        for code in result["bond_codes"]:
            code_str = str(code).strip()
            if re.match(r"^\d{6}$", code_str):
                valid_codes.append(code_str)
        result["bond_codes"] = valid_codes

        # 验证stock_codes格式
        if not isinstance(result["stock_codes"], list):
            result["stock_codes"] = []

        # 过滤有效的股票代码（6位数字）
        valid_stock_codes = []
        for code in result["stock_codes"]:
            code_str = str(code).strip()
            if re.match(r"^\d{6}$", code_str):
                valid_stock_codes.append(code_str)
        result["stock_codes"] = valid_stock_codes
        
        # 验证analysis_dimensions
        valid_dimensions = ["fundamental", "technical", "market", "risk", "macro"]
        if not isinstance(result["analysis_dimensions"], list):
            result["analysis_dimensions"] = valid_dimensions
        else:
            result["analysis_dimensions"] = [
                dim for dim in result["analysis_dimensions"] if dim in valid_dimensions
            ]
            if not result["analysis_dimensions"]:
                result["analysis_dimensions"] = valid_dimensions
        
        # 设置analysis_mode
        if len(result["analysis_dimensions"]) >= 3:
            result["analysis_mode"] = "full"
        else:
            result["analysis_mode"] = "partial"
        
        # 设置enabled_agents
        result["enabled_agents"] = result["analysis_dimensions"].copy()
        if "summary" not in result["enabled_agents"]:
            result["enabled_agents"].append("summary")
        
        # 验证query_type
        if result["intent_type"] != "query":
            result["query_type"] = None
        else:
            valid_query_types = [
                "basic_info",
                "market_data",
                "news",
                "rating",
                "performance",
            ]
            if result["query_type"] not in valid_query_types:
                result["query_type"] = "basic_info"
        
        # 验证confidence
        try:
            result["confidence"] = max(0.0, min(1.0, float(result["confidence"])))
        except (ValueError, TypeError):
            result["confidence"] = 0.5
        
        # 验证time_range
        valid_time_ranges = ["recent", "1month", "3months", "1year", "custom"]
        if result["time_range"] not in valid_time_ranges:
            result["time_range"] = "recent"
        
        # 确保context_awareness字段存在
        if "context_awareness" not in result:
            result["context_awareness"] = {
                "recent_bond_codes": [],
                "recent_stock_codes": [],
                "preferred_dimensions": [],
                "follow_up_target": ""
            }
        
        return result
    
    def _extract_reasoning_steps(self, output: str) -> List[str]:
        """从LLM输出中提取推理步骤"""
        steps = []
        
        # 按句子分割推理过程
        sentences = re.split(r'[。！？\n]', output)
        for sentence in sentences:
            sentence = sentence.strip()
            if sentence and len(sentence) > 10:  # 过滤过短的句子
                steps.append(sentence)
        
        return steps[:5]  # 最多返回5个步骤
    
    def _get_default_result(self, user_input: str, error_msg: str) -> Dict[str, Any]:
        """获取默认的解析结果"""
        
        # 尝试简单的正则表达式提取债券代码
        bond_codes = re.findall(r"\b(\d{6})\b", user_input)
        
        # 简单的关键词检测
        intent_type = "conversation"
        if any(word in user_input for word in ["股票", "个股", "000001", "600000", "000002"]):
            # 如果包含股票关键词，优先判断为股票分析
            if any(word in user_input for word in ["分析", "评估", "看看"]):
                intent_type = "stock_analysis"
            elif any(word in user_input for word in ["查询", "查看", "显示", "多少", "怎么样"]):
                intent_type = "query"
            elif any(word in user_input for word in ["比较", "对比", "哪个更好", "vs"]):
                intent_type = "comparison"
        elif any(word in user_input for word in ["分析", "评估", "看看"]):
            intent_type = "analysis"
        elif any(word in user_input for word in ["查询", "查看", "显示", "多少", "怎么样"]):
            intent_type = "query"
        elif any(word in user_input for word in ["比较", "对比", "哪个更好", "vs"]):
            intent_type = "comparison"
        elif any(word in user_input for word in ["上次", "刚才", "之前", "那个"]):
            intent_type = "follow_up"
        
        # 检测分析维度
        analysis_dimensions = []
        if "基本面" in user_input or "fundamental" in user_input:
            analysis_dimensions.append("fundamental")
        if "技术" in user_input or "technical" in user_input:
            analysis_dimensions.append("technical")
        if "市场" in user_input or "market" in user_input:
            analysis_dimensions.append("market")
        if "风险" in user_input or "risk" in user_input:
            analysis_dimensions.append("risk")
        if "宏观" in user_input or "macro" in user_input:
            analysis_dimensions.append("macro")
        
        if not analysis_dimensions:
            analysis_dimensions = ["fundamental", "technical", "market", "risk", "macro"]
        
        return {
            "intent_type": intent_type,
            "bond_codes": bond_codes,
            "stock_codes": [],  # 默认空股票代码
            "analysis_dimensions": analysis_dimensions,
            "query_type": "basic_info" if intent_type == "query" else None,
            "time_range": "recent",
            "confidence": 0.3,  # 低置信度，因为是回退结果
            "extracted_keywords": [],
            "raw_text": user_input,
            "analysis_mode": "full" if len(analysis_dimensions) >= 3 else "partial",
            "enabled_agents": analysis_dimensions + ["summary"],
            "error": error_msg,
            "status": "fallback",
        }


# 便捷函数
async def parse_user_intent(user_input: str, recent_history: str = "") -> Dict[str, Any]:
    """
    解析用户意图的便捷函数
    
    Args:
        user_input: 用户输入
        recent_history: 对话历史
        
    Returns:
        意图识别结果
    """
    agent = GeneralIntentRecognitionAgent()
    result = await agent.analyze(user_input, recent_history)
    return result["data"] if "data" in result else result


def extract_bond_codes(user_input: str) -> List[str]:
    """
    提取债券代码的便捷函数
    
    Args:
        user_input: 用户输入
        
    Returns:
        债券代码列表
    """
    return re.findall(r"\b(\d{6})\b", user_input)


# 全局实例
general_intent_recognition_agent = GeneralIntentRecognitionAgent()